using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Pavilion;

namespace Pavilion.Control
{
    public class Scroller : Control
    {
        private Panel basePanel, barPanel;
        private Button topButton, bottomButton;
        private int lowerBound, upperBound;
        private float scrollerRatio;
        private Panel panelItem;

        private EventHandler areaBoundsChangedHandler;

        public Scroller() : base()
        {
            AreaBounds = new Rectangle(0, 0, 20, 100);
            topButton = new Button("+", new Rectangle(0, 0, AreaBounds.Width, AreaBounds.Width), 0.5f);
            bottomButton = new Button("+", new Rectangle(0, AreaBounds.Height - AreaBounds.Width, AreaBounds.Width, AreaBounds.Width), 0.5f);
            basePanel = new Panel(new Rectangle(0, topButton.AreaBounds.Height, AreaBounds.Width, AreaBounds.Height - topButton.AreaBounds.Height - bottomButton.AreaBounds.Height));
            barPanel = new Panel(new Rectangle(2, 2, basePanel.AreaBounds.Width - 4, basePanel.AreaBounds.Height - 4));
            barPanel.BackgroundColor = new Color(0, 0, 0, 128);

            basePanel.Collection.Add(barPanel);
            _Collection.Add(basePanel);
            _Collection.Add(topButton);
            _Collection.Add(bottomButton);

            topButton.Pressed += new Action(topButton_Pressed);
            bottomButton.Pressed += new Action(bottomButton_Pressed);
            this.Resize += new EventHandler(Scroller_Resize);
            RootControl.Instance.MouseCursor.ScrollWheelChanged += new Action<MouseCursor>(Scroller_ScrollWheelChanged);

            areaBoundsChangedHandler = new EventHandler(Control_AreaBoundsChanged);
        }

        public void AttachPanel(Panel panel)
        {
            PanelItem = panel;

            CalculateBarSize();
        }

        public void ResetPosition()
        {
            int distance = -barPanel.Position.Y + 2;

            ScrollBar(distance);
        }

        private void CalculateBarSize()
        {
            if (panelItem == null)
            {
                barPanel.AreaBounds = new Rectangle(2, 2, basePanel.AreaBounds.Width - 4, basePanel.AreaBounds.Height - 4);
                return;
            }

            lowerBound = 0;
            upperBound = 0;

            if (panelItem.AreaBounds.Height + panelItem.AreaBounds.Y > AreaBounds.Bottom)
                lowerBound = panelItem.AreaBounds.Height + panelItem.AreaBounds.Y - (AreaBounds.Bottom);

            if (panelItem.AreaBounds.Y < AreaBounds.Y)
                upperBound = AreaBounds.Y - panelItem.AreaBounds.Y;

            float baseRatio = (float)AreaBounds.Height / (float)(AreaBounds.Height + lowerBound + upperBound);
            float scrollerHeight = (float)(basePanel.AreaBounds.Height - 4) * baseRatio;
            scrollerRatio = (scrollerHeight / (float)AreaBounds.Height);
            barPanel.AreaBounds = new Rectangle(2, (int)(scrollerRatio * upperBound) + 2, basePanel.AreaBounds.Width - 4, (int)scrollerHeight);
        }

        private void ScrollBar(int scrollSpeed)
        {
            //if (barPanel.AreaBounds.Height + barPanel.AreaBounds.Y > basePanel.AreaBounds.Height - 2 || barPanel.AreaBounds.Y < 2)
            //    return;

            if (barPanel.AreaBounds.Height + barPanel.AreaBounds.Y + scrollSpeed > basePanel.AreaBounds.Height - 2)
                scrollSpeed = (basePanel.AreaBounds.Height - 3) - (barPanel.AreaBounds.Height + barPanel.AreaBounds.Y);
            else if (barPanel.AreaBounds.Y + scrollSpeed < 2)
                scrollSpeed = -(barPanel.AreaBounds.Y - 2);

            float distance = (float)scrollSpeed / scrollerRatio;

            barPanel.Position = new Point(barPanel.Position.X, barPanel.Position.Y + scrollSpeed);
            panelItem.Position = new Point(panelItem.AreaBounds.X, panelItem.AreaBounds.Y - (int)distance);
        }

        /// <summary>
        /// Gets or sets the maximum height of this scroller.
        /// </summary>
        public int MaximumHeight
        {
            get { return AreaBounds.Height; }
            set
            {
                AreaBounds = new Rectangle(AreaBounds.X, AreaBounds.Y, AreaBounds.Width, value);
                ResetPosition();
            }
        }

        /// <summary>
        /// Gets or sets the Panel item that is attached to this scroller.
        /// </summary>
        private Panel PanelItem
        {
            get { return panelItem; }
            set
            {
                if (panelItem != null)
                {
                    panelItem.Resize -= areaBoundsChangedHandler;
                    panelItem.Reposition -= areaBoundsChangedHandler;
                }

                this.panelItem = value;

                if (panelItem != null)
                {
                    panelItem.Resize += areaBoundsChangedHandler;
                    panelItem.Reposition += areaBoundsChangedHandler;
                    AreaBounds = new Rectangle(panelItem.AreaBounds.X + panelItem.AreaBounds.Width, panelItem.AreaBounds.Y, AreaBounds.Width, AreaBounds.Height);
                }
            }
        }

        private void bottomButton_Pressed()
        {
            ScrollBar((int)(10f / scrollerRatio));
        }

        private void topButton_Pressed()
        {
            ScrollBar(-(int)(10f / scrollerRatio));
        }

        private void Control_AreaBoundsChanged(object sender, EventArgs e)
        {
            CalculateBarSize();
        }

        private void Scroller_Resize(object sender, EventArgs e)
        {
            topButton.AreaBounds = new Rectangle(0, 0, AreaBounds.Width, AreaBounds.Width);
            bottomButton.AreaBounds = new Rectangle(0, AreaBounds.Height - AreaBounds.Width, AreaBounds.Width, AreaBounds.Width);
            basePanel.AreaBounds = new Rectangle(0, topButton.AreaBounds.Height, AreaBounds.Width, AreaBounds.Height - topButton.AreaBounds.Height - bottomButton.AreaBounds.Height);

            CalculateBarSize();
        }

        private void Scroller_ScrollWheelChanged(MouseCursor mouseCursor)
        {
            ScrollBar(-(int)(mouseCursor.ScrollWheelRange * (10f/scrollerRatio)));
        }
    }
}
